package edu.cmu.vlis.wassup.coordinator;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;

/**
 * This class encapsulates Message processor or poller process.
 * Contains info like on which node it is running, type of process.
 * This is not an actual process rather a proxy for the one running on
 * nodes.
 */
public class Process {

    private Node host;
    private int port;
    private String name;
    private Socket socket;
    private PrintWriter writer;
    private String pingMsg = "ALIVE?";
    private BufferedReader reader;

    /**
     * @param host
     * @param port
     */
    public Process(Node host, int port,String name) {
        super();
        this.host = host;
        this.port = port;
        this.name = name;
    }

    public boolean startSocket()  {

        System.out.println("Connection to: "+host.getIpAdd()+"\t"+this.getPort());
        try {
            this.socket = new Socket(host.getIpAdd(),this.getPort());
            this.writer = new PrintWriter(this.socket.getOutputStream(),true);
            this.reader = new BufferedReader(new InputStreamReader(this.socket.getInputStream()));
            return true;
        } catch (UnknownHostException e) {
        	return false;
            e.printStackTrace();
        } catch (IOException e) {
        	return false;
         //   e.printStackTrace();
        }
    }
    
    public boolean closeSocket()  {

        System.out.println("Closing "+host.getIpAdd()+"\t"+this.getPort());
        try {
            this.socket = null;
            this.writer = null;
            this.reader = null;
            return true;
        } catch (UnknownHostException e) {
        	return false;
            e.printStackTrace();
        } catch (IOException e) {
        	return false;
         //   e.printStackTrace();
        }
    }

    public boolean sendRestartMsg(String msg){

        if(this.socket == null || !socket.isBound() || socket.isClosed() || !socket.isConnected() || socket.isInputShutdown() || socket.isOutputShutdown())
            return false;

        this.writer.println(msg);
        this.writer.flush();
        try {
            Thread.sleep(5000);
            String response = this.reader.readLine();
            if(response != null && response.equalsIgnoreCase("Yes"))
                return true;
            if(response != null && response.equalsIgnoreCase("No"))
                return false;
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return false;
        
    }
    public boolean isAlive(){
        
        if(this.socket == null || !socket.isBound() || socket.isClosed() || !socket.isConnected() || socket.isInputShutdown() || socket.isOutputShutdown())
            return false;

        this.writer.println(pingMsg);
        this.writer.flush();
        System.out.println("send a alive to process!");
        try {
        	Thread.sleep(1000);
            String response = this.reader.readLine();
            if(response != null && response.equalsIgnoreCase("Yes"))
                return true;
        } catch (IOException e) {
            System.err.println("Cordinator lost conn to: "+this.getName()+" "+this.host.getIpAdd()+" "+this.getPort());
            //e.printStackTrace();
        } catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
        return false;
    }
    /**
     * @return the host
     */
    public Node getHost() {
        return host;
    }

    public void setHost(Node n){
        this.host = n;
    }
    public void setName(String name){
        this.name = name;
    }
    /**
     * @return the port
     */
    public int getPort() {
        return port;
    }
    
    public String getName() {
        return name;
    }
    public String getType(){
        return null;
    }

    /**
     * @param port the port to set
     */
    public void setPort(int port) {
        this.port = port;
    }
}
